home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_0_m.arj / GPFILT.ASM < prev    next >
Assembly Source File  |  1988-04-20  |  27KB  |  573 lines

  1.         page    ,132
  2.         TITLE   GPFILT
  3.         subttl  General Purpose Filter Template
  4. ;
  5. ; GPFILT.ASM
  6. ; This file contains a template for a general-purpose assembly language
  7. ; filter program.
  8. ;
  9. ; Fill in the blanks for what you wish to do.  The program is set up to
  10. ; accept a command line in the form:
  11. ;       COMMAND [{-|/}options] [infile [outfile]]
  12. ;
  13. ; If infile is not specified, stdin is used.
  14. ; If outfile is not specified, stdout is used.
  15. ;
  16. ; To compile and link:
  17. ;    MASM GPFILT ;
  18. ;    LINK GPFILT ;
  19. ;    EXE2BIN GPFILT GPFILT.COM
  20. ;
  21. ; Standard routines supplied in the general shell are:
  22. ;
  23. ; get_arg - returns the address of the next command line argument in
  24. ;           DX.  Since this is a .COM file, the routine assumes DS will
  25. ;           be the same as the command line segment.
  26. ;           The routine will return with Carry set when it reaches the end
  27. ;           of the command line.
  28. ;
  29. ; err_msg - displays an ASCIIZ string on the STDERR device.  Call with the
  30. ;           address of the string in ES:DX.
  31. ;
  32. ; do_usage- displays the usage message on the STDERR device and exits
  33. ;           with an error condition (errorlevel 1).  This routine will
  34. ;           never return.
  35. ;
  36. ; getch   - returns the next character from the input stream in AL.
  37. ;           It will return with carry set if an error occurs during read.
  38. ;           It will return with the ZF set at end of file.
  39. ;
  40. ; putch   - writes a character from AL to the output stream.  Returns with
  41. ;           carry set if a write error occurs.
  42. ;
  43. cseg    segment
  44.         assume cs:cseg, ds:cseg, es:cseg, ss:cseg
  45.  
  46.         org     0100h                   ;for .COM files
  47.  
  48. start:  jmp     main                    ;jump around data area
  49.  
  50. ;
  51. ; Equates and global data area.
  52. ;
  53. ; The following equates and data areas are required by the general filter
  54. ; routines.  User data area follows.
  55. ;
  56. STDIN   equ     0
  57. STDOUT  equ     1
  58. STDERR  equ     2
  59. STDPRN  equ     3
  60. cr      equ     0dh
  61. lf      equ     0ah
  62. space   equ     32
  63. tab     equ     9
  64.  
  65. infile  dw      STDIN                   ;default input file is stdin
  66. outfile dw      STDOUT                  ;default output file is stdout
  67. errfile dw      STDERR                  ;default error file is stderr
  68. prnfile dw      STDPRN                  ;default print file is stdprn
  69. cmd_ptr dw      0081h                   ;address of first byte of command tail
  70. PSP_ENV equ     002ch                   ;The segment address of the environment 
  71.                                         ;block is stored here.
  72.  
  73. infile_err      db      cr, lf, 'Error opening input file', 0
  74. outfile_err     db      cr, lf, 'Error opening output file', 0
  75. aborted         db      07, cr, lf, 'Program aborted', 0
  76. usage           db      cr, lf, 'Usage: ', 0
  77. crlf            db      cr, lf, 0
  78.  
  79. ;************************************************************************
  80. ;*                                                                      *
  81. ;* Buffer sizes for input and output files.  The buffers need not be    *
  82. ;* the same size.  For example, a program that removes tabs from a text *
  83. ;* file will output more characters than it reads.  Therefore, the      *
  84. ;* output buffer should be slightly larger than the input buffer.  In   *
  85. ;* general, the larger the buffer, the faster the program will run.     *
  86. ;*                                                                      *
  87. ;* The only restriction here is that the combined size of the buffers   *
  88. ;* plus the program code and data size cannot exceed 64K.               *
  89. ;*                                                                      *
  90. ;* The easiest way to determine maximum available buffer memory is to   *
  91. ;* assemble the program with minimum buffer sizes and examine the value *
  92. ;* of the endcode variable at the end of the program.  Subtracting this *
  93. ;* value from 65,536 will give you the total buffer memory available.   *
  94. ;*                                                                      *
  95. ;************************************************************************
  96. ;
  97. INNBUF_SIZE     equ     31              ;size of input buffer (in K)
  98. OUTBUF_SIZE     equ     31              ;size of output buffer (in K)
  99.  
  100. ;
  101. ;************************************************************************
  102. ;*                                                                      *
  103. ;* Data definitions for input and output buffers.  DO NOT modify these  *
  104. ;* definitions unless you know exactly what it is you're doing!        *
  105. ;*                                                                      *
  106. ;************************************************************************
  107. ;
  108. ; Input buffer
  109. ibfsz   equ     1024*INNBUF_SIZE        ;input buffer size in bytes
  110. inbuf   equ     endcode                 ;input buffer
  111. ibfend  equ     inbuf + ibfsz           ;end of input buffer
  112. ;
  113. ; ibfptr is initialized to point past end of input buffer so that the first
  114. ; call to getch will result in a read from the file.
  115. ;
  116. ibfptr  dw      inbuf+ibfsz
  117.  
  118. ; output buffer
  119. obfsz   equ     1024*OUTBUF_SIZE        ;output buffer size in bytes
  120. outbuf  equ     ibfend                  ;output buffer
  121. obfend  equ     outbuf + obfsz          ;end of output buffer
  122. obfptr  dw      outbuf                  ;start at beginning of buffer
  123.  
  124. ;************************************************************************
  125. ;*                                                                      *
  126. ;*                            USER DATA AREA                            *
  127. ;*                                                                      *
  128. ;*      Insert any data declarations specific to your program here.     *
  129. ;*                                                                      *
  130. ;* NOTE:  The prog_name, use_msg, and use_msg1 variables MUST be        *
  131. ;*        defined.                                                      *
  132. ;*                                                                      *
  133. ;************************************************************************
  134. ;
  135. ; This is the program name.  Under DOS 3.x, this is not used because we
  136. ; can get the program name from the environment.  Prior to 3.0, this
  137. ; information is not supplied by the OS.
  138. ;
  139. prog_name       db      'GPFILT', 0
  140. ;
  141. ; This is the usage message.  The first two lines are required.
  142. ; The first line is the programs title line.
  143. ;   Make sure to include the 0 at the end of the first line!!
  144. ; The second line shows the syntax of the program.
  145. ; Following lines (which are optional), are discussion of options, features, 
  146. ; etc...
  147. ; The message MUST be terminated by a 0.
  148. ;
  149. use_msg db      ' - General Purpose FILTer program.', cr, lf, 0
  150. use_msg1        label byte
  151.         db      '[{-|/}options] [infile [outfile]]', cr, lf
  152.         db      cr, lf
  153.         db      'If infile is not specified, STDIN is used', cr, lf
  154.         db      'If outfile is not specified, STDOUT is used', cr, lf
  155.         db      0
  156. ;
  157. ;************************************************************************
  158. ;*                                                                      *
  159. ;* The main routine parses the command line arguments, opens files, and *
  160. ;* does other initialization tasks before calling the filter procedure  *
  161. ;* to do the actual work.                                               *
  162. ;* For a large number of filter programs, this routine will not need to *
  163. ;* be modified.  Options are parsed in the get_options proc., and the   *
  164. ;* filter proc. does all of the 'filter' work.                          *
  165. ;*                                                                      *
  166. ;************************************************************************
  167. ;
  168. main:   cld
  169.         call    get_options             ;process options
  170.         jc      gofilter                ;carry indicates end of arg list
  171.         mov     ah,3dh                  ;open file
  172.         mov     al,0                    ;read access
  173.         int     21h                     ;open the file
  174.         mov     word ptr ds:[infile], ax ;save file handle
  175.         jnc     main1                   ;carry clear indicates success
  176.         mov     dx,offset infile_err
  177.         jmp     short err_exit
  178. main1:  call    get_arg                 ;get cmd line arg in DX
  179.         jc      gofilter                ;carry indicates end of arg list
  180.         mov     ah,3ch                  ;create file
  181.         mov     cx,0                    ;normal file
  182.         int     21h                     ;open the file
  183.         mov     word ptr ds:[outfile],ax ;save file handle
  184.         jnc     gofilter                ;carry clear indicates success
  185.         mov     dx,offset outfile_err
  186.         jmp     short err_exit
  187. gofilter:
  188.         call    filter                  ;do the work
  189.         jc      err_exit                ;exit immediately on error
  190.         mov     ah,3eh
  191.         mov     bx,word ptr [infile]
  192.         int     21h                     ;close input file
  193.         mov     ah,3eh
  194.         mov     bx,word ptr [outfile]
  195.         int     21h                     ;close output file
  196.         mov     ax,4c00h
  197.         int     21h                     ;exit with no error
  198. err_exit:
  199.         call    err_msg                 ;output error message
  200.         mov     dx,offset aborted
  201.         call    err_msg
  202.         mov     ax,4c01h
  203.         int     21h                     ;and exit with error
  204. ;
  205. ;************************************************************************
  206. ;*                                                                      *
  207. ;* get_options processes any command line options.  Options are         *
  208. ;* preceeded by either - or /.  There is a lot of flexibility here.     *
  209. ;* Options can be specified separately, or as a group.  For example,    *
  210. ;* the command "GPFILT -x -y -z" is equivalent to "GPFILT -xyz".        *
  211. ;*                                                                      *
  212. ;* This routine MUST return the address of the next argument in DX or   *
  213. ;* carry flag set if there are no more options.  In other words, return *
  214. ;* what was returned by the last call to get_arg.                       *
  215. ;*                                                                      *
  216. ;************************************************************************
  217. ;
  218. get_options     proc
  219.         call    get_arg                 ;get command line arg
  220.         jnc     opt1
  221. ; If at least one argument is required, use this line
  222. ;       call    do_usage                ;displays usage msg and exits
  223. ; If there are no required args, use this line
  224.         ret                             ;if no args, just return
  225. opt1:   mov     di, dx
  226.         mov     al,byte ptr ds:[di]
  227.         cmp     al,'-'                  ;if first character of arg is '-'
  228.         jz      opt_parse
  229.         cmp     al,'/'                  ;or '/', then get options
  230.         jz      opt_parse
  231.         ret                             ;otherwise exit
  232. opt_parse:
  233.         inc     di
  234.         mov     al,byte ptr ds:[di]
  235.         or      al,al                   ;if end of options string
  236.         jz      nxt_opt                 ;get cmd. line arg
  237.         cmp     al,'?'                  ;question means show usage info
  238.         jz      do_usage
  239. ;
  240. ;************************************************************************
  241. ;*                                                                      *
  242. ;* Code for processing other options goes here.  The current option     *
  243. ;* character is in AL, and the remainder of the option string is pointed*
  244. ;* to by DS:DI.                                                         *
  245. ;*                                                                      *
  246. ;************************************************************************
  247. ;
  248.         jmp     short opt_parse
  249.  
  250. nxt_opt:
  251.         call    get_arg                 ;get next command line arg
  252.         jnc     opt1                    ;if carry
  253. vld_args:                               ;then validate arguments
  254. ;
  255. ;************************************************************************
  256. ;*                                                                      *
  257. ;* Validate arguments.  If some options are mutually exclusive/dependent*
  258. ;* use this area to validate them.  Whatever the case, if you must      *
  259. ;* abort the program, call the do_usage procedure to display the usage  *
  260. ;* message and exit the program.                                        *
  261. ;*                                                                      *
  262. ;************************************************************************
  263. ;
  264.         ret                             ; no more options
  265. ;
  266. ;************************************************************************
  267. ;*                                                                      *
  268. ;* Filter does all the work.  Modify this routine to do what it is you  *
  269. ;* need done.                                                           *
  270. ;*                                                                      *
  271. ;************************************************************************
  272. ;
  273. filter  proc
  274.         call    getch                   ;get a character from input into AL
  275.         jbe     filt_done               ;exit on error or EOF
  276.         and     al, 7fh                 ;strip the high bit
  277.         call    putch                   ;and output it
  278.         jc      filt_ret                ;exit on error
  279.         jmp     short filter
  280. filt_done:
  281.         jc      filt_ret                ;carry set is error
  282.         call    write_buffer            ;output what remains of the buffer
  283. filt_ret:
  284.         ret
  285. filter  endp
  286. ;
  287. ;************************************************************************
  288. ;*                                                                      *
  289. ;*              Put any program-specific routines here                  *
  290. ;*                                                                      *
  291. ;************************************************************************
  292.  
  293. ;
  294. ;************************************************************************
  295. ;*                                                                      *
  296. ;* For most programs, nothing beyond here should require modification.  *
  297. ;* The routines that follow are standard routines used by almost every  *
  298. ;* filter program.                                                      *
  299. ;*                                                                      *
  300. ;************************************************************************
  301. ;
  302. ;************************************************************************
  303. ;*                                                                      *
  304. ;* This routine outputs the usage message to the STDERR device and      *
  305. ;* aborts the program with an error code.  A little processing is done  *
  306. ;* here to get the program name and format the output.                  *
  307. ;*                                                                      *
  308. ;************************************************************************
  309. ;
  310. do_usage:
  311.         mov     dx, offset crlf
  312.         call    err_msg                 ;output newline
  313.         mov     ah,30h                  ;get DOS version number
  314.         int     21h
  315.         sub     al,3                    ;check for version 3.x
  316.         jc      lt3                     ;if carry, earlier than 3.0
  317. ;
  318. ; For DOS 3.0 and later the full pathname of the file used to load this
  319. ; program is stored at the end of the environment block.  We first scan
  320. ; all of the environment strings in order to find the end of the env, then
  321. ; scan the load pathname looking for the file name.
  322. ;
  323.         push    es
  324.         mov     ax, word ptr ds:[PSP_ENV]
  325.         mov     es, ax                  ;ES is environment segment address
  326.         mov     di, 0
  327.         mov     cx, 0ffffh              ;this ought to be enuf
  328.         xor     ax, ax
  329. getvar: scasb                           ;get char
  330.         jz      end_env                 ;end of environment
  331. gv1:    repnz   scasb                   ;look for end of variable
  332.         jmp     short getvar            ;and loop 'till end of environment
  333. end_env:
  334.         inc     di
  335.         inc     di                      ;bump past word count
  336. ;
  337. ; ES:DI is now pointing to the beginning of the pathname used to load the 
  338. ; program.  We will now scan the filename looking for the last path specifier
  339. ; and use THAT address to output the program name.  The program name is
  340. ; output WITHOUT the extension.
  341. ;
  342.         mov     dx, di
  343. fnloop: mov     al, byte ptr es:[di]
  344.         or      al, al                  ;if end of name
  345.         jz      do30                    ;then output it
  346.         inc     di
  347.         cmp     al, '\'                 ;if path specifier
  348.         jz      updp                    ;then update path pointer
  349.         cmp     al, '.'                 ;if '.'
  350.         jnz     fnloop
  351.         mov     byte ptr es:[di-1], 0   ;then place a 0 so we don't get ext
  352.         jmp     short fnloop            ; when outputting prog name
  353. updp:   mov     dx, di                  ;store
  354.         jmp     short fnloop
  355. ;
  356. ; ES:DX now points to the filename of the program loaded (without extension).
  357. ; Output the program name and then go on with rest of usage message.
  358. ;
  359. do30:   call    err_msg                 ;output program name
  360.         pop     es                      ;restore
  361.         jmp     short gopt3
  362. ;
  363. ; We arrive here if the current DOS version is earlier than 3.0.  Since the
  364. ; loaded program name is not available from the OS, we'll output the name
  365. ; entered in the 'prog_name' field above.
  366. ;
  367. lt3:    mov     dx, offset prog_name
  368.         call    err_msg                 ;output the program name
  369. ;
  370. ; After outputting program name, we arrive here to output the rest of the
  371. ; usage message.  This code assumes that the usage message has been
  372. ; written as specified in the data area.
  373. ;
  374. gopt3:  mov     dx, offset use_msg
  375.         call    err_msg                 ;output the message
  376.         mov     dx, offset usage
  377.         call    err_msg
  378.         mov     dx, offset use_msg1
  379.         call    err_msg
  380.         mov     ax,4c01h
  381.         int     21h                     ;and exit with error
  382. get_options     endp    
  383.  
  384. ;
  385. ;************************************************************************
  386. ;*                                                                      *
  387. ;* Output a message (ASCIIZ string) to the standard error device.       *
  388. ;* Call with address of error message in ES:DX.                         *
  389. ;*                                                                      *
  390. ;************************************************************************
  391. ;
  392. err_msg proc
  393.         cld
  394.         mov     di,dx                   ;string address in di
  395.         mov     cx,0ffffh
  396.         xor     ax,ax
  397.         repnz   scasb                   ;find end of string
  398.         xor     cx,0ffffh
  399.         dec     cx                      ;CX is string length
  400.         push    ds
  401.         mov     ax,es
  402.         mov     ds,ax                   ;DS is segment address
  403.         mov     ah,40h
  404.         mov     bx,word ptr cs:[errfile]
  405.         int     21h                     ;output message
  406.         pop     ds
  407.         ret
  408. err_msg endp
  409.  
  410. ;
  411. ;************************************************************************
  412. ;*                                                                      *
  413. ;* getch returns the next character from the file in AL.                *
  414. ;* Returns carry = 1 on error                                           *
  415. ;*         ZF = 1 on EOF                                                *
  416. ;* Upon exit, if either Carry or ZF is set, the contents of AL is       *
  417. ;* undefined.                                                           *
  418. ;*                                                                      *
  419. ;************************************************************************
  420. ;
  421. ; Local variables used by the getch proc.
  422. eof     db      0                       ;set to 1 when EOF reached in read
  423. last_ch dw      ibfend                  ;pointer to last char in buffer
  424.  
  425. getch   proc
  426.         mov     si,word ptr ds:[ibfptr] ;get input buffer pointer
  427.         cmp     si,word ptr ds:[last_ch];if not at end of buffer
  428.         jz      getch_eob
  429. getch1: lodsb                           ;character in AL
  430.         mov     word ptr ds:[ibfptr],si ;save buffer pointer
  431.         or      ah,1                    ;will clear Z flag
  432.         ret                             ;and done
  433.  
  434. getch_eob:                              ;end of buffer processing
  435.         cmp     byte ptr ds:[eof], 1    ;end of file?
  436.         jnz     getch_read              ;nope, read file into buffer
  437. getch_eof:
  438.         xor     ax, ax                  ;set Z to indicate EOF
  439.         ret                             ;and return
  440.  
  441. getch_read:                     ; Read the next buffer full from the file.
  442.         mov     ah,3fh                  ;read file function
  443.         mov     bx,word ptr ds:[infile] ;input file handle
  444.         mov     cx,ibfsz                ;#characters to read
  445.         mov     dx,offset inbuf         ;read into here
  446.         int     21h                     ;DOS'll do it for us
  447.         jc      read_err                ;Carry means error
  448.         or      ax,ax                   ;If AX is zero,
  449.         jz      getch_eof               ;we've reached end-of-file
  450.         add     ax,offset inbuf
  451.         mov     word ptr ds:[last_ch],ax;and save it
  452.         mov     si,offset inbuf
  453.         jmp     short getch1            ;and finish processing character
  454.                 
  455. read_err:                               ;return with error and...
  456.         mov     dx,offset read_err_msg  ; DX pointing to error message string
  457.         ret
  458. read_err_msg    db      'Read error', cr, lf, 0
  459. getch   endp
  460.  
  461. ;
  462. ;************************************************************************
  463. ;*                                                                      *
  464. ;* putch writes the character passed in AL to the output file.          *
  465. ;* Returns carry set on error.  The character in AL is retained.        *
  466. ;*                                                                      *
  467. ;************************************************************************
  468. ;
  469. putch   proc
  470.         mov     di,word ptr ds:[obfptr] ;get output buffer pointer
  471.         stosb                           ;save the character
  472.         mov     word ptr ds:[obfptr],di ;and update buffer pointer
  473.         cmp     di,offset obfend        ;if buffer pointer == buff end
  474.         clc
  475.         jnz     putch_ret
  476.         push    ax
  477.         call    write_buffer            ;then we've got to write the buffer
  478.         pop     ax
  479. putch_ret:
  480.         ret
  481. putch   endp
  482.  
  483. ;
  484. ;************************************************************************
  485. ;*                                                                      *
  486. ;* write_buffer writes the output buffer to the output file.            *
  487. ;* This routine should not be called except by the putch proc. and at   *
  488. ;* the end of all processing (as demonstrated in the filter proc).      *
  489. ;*                                                                      *
  490. ;************************************************************************
  491. ;
  492. write_buffer    proc                    ;write buffer to output file
  493.         mov     ah, 40h                 ;write to file function
  494.         mov     bx, word ptr ds:[outfile];output file handle
  495.         mov     cx, word ptr ds:[obfptr]
  496.         sub     cx, offset outbuf       ;compute #bytes to write
  497.         mov     dx, offset outbuf       ;from this buffer
  498.         int     21h                     ;DOS'll do it
  499.         jc      write_err               ;carry is error
  500.         or      ax,ax                   ;return value of zero
  501.         jz      putch_full              ;indicates disk full
  502.         mov     word ptr ds:[obfptr],offset outbuf
  503.         clc
  504.         ret
  505.  
  506. putch_full:                             ;disk is full
  507.         mov     dx,offset disk_full
  508.         stc                             ;exit with error
  509.         ret
  510.  
  511. write_err:                              ;error occured during write
  512.         mov     dx,offset write_err_msg
  513.         stc                             ;return with error
  514.         ret
  515. write_err_msg   db      'Write error', cr, lf, 0
  516. disk_full       db      'Disk full', cr, lf, 0
  517.  
  518. write_buffer    endp
  519.  
  520. ;
  521. ;************************************************************************
  522. ;*                                                                      *
  523. ;* get_arg - Returns the address of the next command line argument in   *
  524. ;* DX.  The argument is in the form of an ASCIIZ string.                *
  525. ;* Returns Carry = 1 if no more command line arguments.                 *
  526. ;* Upon exit, if Carry is set, the contents of DX is undefined.         *
  527. ;*                                                                      *
  528. ;************************************************************************
  529. ;
  530. get_arg proc
  531.         mov     si,word ptr [cmd_ptr]
  532. skip_space:                             ;scan over leading spaces and commas
  533.         lodsb
  534.         cmp     al,0                    ;if we get a null
  535.         jz      sk0
  536.         cmp     al,cr                   ;or a CR,
  537.         jnz     sk1
  538. sk0:    stc                             ;set carry to indicate failure
  539.         ret                             ;and exit
  540. sk1:    cmp     al,space
  541.         jz      skip_space              ;loop until no more spaces
  542.         cmp     al,','
  543.         jz      skip_space              ;or commas
  544.         cmp     al,tab
  545.         jz      skip_space              ;or tabs
  546.  
  547.         mov     dx,si                   ;start of argument
  548.         dec     dx
  549. get_arg1:
  550.         lodsb                           ;get next character
  551.         cmp     al,cr                   ;argument seperators are CR,
  552.         jz      get_arg2
  553.         cmp     al,space                ;space,
  554.         jz      get_arg2
  555.         cmp     al,','                  ;comma,
  556.         jz      get_arg2
  557.         cmp     al,tab                  ;and tab
  558.         jnz     get_arg1
  559.  
  560. get_arg2:
  561.         mov     byte ptr ds:[si-1], 0   ;delimit argument with 0
  562.         cmp     al, cr                  ;if char is CR then we've reached
  563.         jnz     ga2                     ; the end of the argument list
  564.         dec     si
  565. ga2:    mov     word ptr ds:[cmd_ptr], si ;save for next time 'round
  566.         ret                             ;and return
  567. get_arg endp
  568.  
  569. endcode equ     $
  570.  
  571. cseg    ends
  572.         end     start
  573.